package java学习.第10章_多线程的入门;


import java.security.SecureRandom;
import java.util.concurrent.*;

/**
 * 线程池的优势:
 * 线程池做的工作只要是控制运行的线程数量，处理过程中将任务放入队列，然后在线程创建后启动这些任务，
 * 如果线程数量超过了最大数量，超出数量的线程排队等候，等其他线程执行完毕，再从队列中取出任务来执行。
 * 它的主要特点为:线程复用;控制最大并发数;管理线程。
 * 第一:降低资源消耗。通过重复利用己创建的线程降低线程创建和销毁造成的销耗。
 * 第二:提高响应速度。当任务到达时，任务可以不需要等待线程创建就能立即执行。
 * 第三:提高线程的可管理性。线程是稀缺资源，如果无限制的创建，
 *      不仅会销耗系统资源，还会降低系统的稳定性，
 *      使用线程池可以进行统一的分配，调优和监控。
 *
 * 背景:经常创建和销毁、使用量特别大的资源，比如并发情况下的线程，
 * 对性能影响很大。
 * 思路:提前创建好多个线程，放入线程池中，使用时直接获取，使用完
 * 放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交
 * 通工具。
 * ●好处:
 *      ➢提高响应速度(减少了创建新线程的时间)
 *      ➢降低资源消耗(重复利用线程池中线程，不需要每次都创建)
 *      ➢便于线程管理
 */
public class I_线程池 {
    static SecureRandom s = new SecureRandom();
    public static void main(String[] args) {

        ewFixedThreadPool_demo();
    }

    /**
     * 源码
     * public ThreadPoolExecutor(int corePoolSize,          //线程池中常驻核心线程数
     *                               int maximumPoolSize,    //线程池中最多同时容纳最大线程数   必须大于0
     *                               long keepAliveTime,     //线程存活时间
     *                               TimeUnit unit,          //时间单位
     *                               BlockingQueue<Runnable> workQueue,  //阻塞队列  任务队列 被提交但尚未被执行的任务
     *                               ThreadFactory threadFactory,    //表示生成线程池中工作线程的线程工厂  用于创建线程  一般默认
     *                               RejectedExecutionHandler handler) {  //RejectedExecutionHandle 拒绝策略  当队列满了  工作线程大于等于最大线程数   拒绝再来的
     *         if (corePoolSize < 0 ||
     *             maximumPoolSize <= 0 ||
     *             maximumPoolSize < corePoolSize ||
     *             keepAliveTime < 0)
     *             throw new IllegalArgumentException();
     *         if (workQueue == null || threadFactory == null || handler == null)
     *             throw new NullPointerException();
     *         this.acc = System.getSecurityManager() == null ?
     *                 null :
     *                 AccessController.getContext();
     *         this.corePoolSize = corePoolSize;
     *         this.maximumPoolSize = maximumPoolSize;
     *         this.workQueue = workQueue;
     *         this.keepAliveTime = unit.toNanos(keepAliveTime);
     *         this.threadFactory = threadFactory;
     *         this.handler = handler;
     *     }
     *
     *
     */
    private static void ewFixedThreadPool_demo() {

        /**
         * 线程池参数
         * 1：return new ThreadPoolExecutor(nThreads, nThreads,
         *                                       0L, TimeUnit.MILLISECONDS,
         *                                       new LinkedBlockingQueue<Runnable>());
         *
         * 2： return new FinalizableDelegatedExecutorService
         *             (new ThreadPoolExecutor(1, 1,
         *                                     0L, TimeUnit.MILLISECONDS,
         *                                     new LinkedBlockingQueue<Runnable>()));
         *
         * 3：ThreadPoolExecutor(0, Integer.MAX_VALUE,
         *  60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
         *
         */


        /**
         * 系统给的线程池
         * 都不用   容易OOM
         *
         * ExecutorService threadPool= Executors.newFixedThreadPool(5);
         * 线程池   nTreads  几个线程  类似银行多个窗口        固定  线程  池
         * ExecutorService threadPool= Executors.newSingleThreadExecutor();
         * 线程池  一个  线程   类似一个窗口
         * ExecutorService threadPool= Executors.newCachedThreadPool();
         *           自动扩容线程 不够就添加
         */


        ExecutorService threadPool= new ThreadPoolExecutor(
                2,//核心线程数 == 固定线程数
                5,//最大线程数

                /**
                 * 1、对于CPU密集型，也就是代码大部分操作都是CPU去执行计算处理的，
                 *                 不需要创建过多的线程，所以可以设置为 CPU核数+1
                 * 2、对于IO密集型，因为IO操作往往伴随着线程的线程的使用，
                 *                所以应该设置大一些，所以可以设置为 CPU核数*2
                 *                或者是  CPU核数/（1-阻塞系数）    阻塞系数一般是0.8-0.9
                 * System.out.println(Runtime.getRuntime().availableProcessors());//看你几核处理器
                 *
                 * 当LinkedBlockingDeque队列  满了 加到maximumPoolSize
                 * 当在自己定的时间 内  没事干了  会销毁多的
                 *
                 */

                2L,//线程存活时间
                TimeUnit.SECONDS,//时间单位
                /**
                 * 当非核心线程空闲时间超过给的时间时，会自动回收非核心线程
                 */
                new LinkedBlockingDeque<>(3), //阻塞队列
                Executors.defaultThreadFactory(),//表示生成线程池中工作线程的线程工厂  用于创建线程  一般默认
                new ThreadPoolExecutor.CallerRunsPolicy()//拒绝策略  当阻塞队列满了  工作线程大于等于最大线程数时触发
        );



                /*
                    Policy//策略
                    new ThreadPoolExecutor.DiscardPolicy()//抛弃执行不了的        丢弃策略
                    new ThreadPoolExecutor.DiscardOldestPolicy()//抛弃等待最久的  丢弃最旧的策略
                    new ThreadPoolExecutor.CallerRunsPolicy()// 会退回原有的线程   呼叫方运行策略
                    new ThreadPoolExecutor.AbortPolicy()  不够会抛异常 默认的      中止政策
                */  //处理结果

        //java.util.concurrent.RejectedExecutionException   太多了  最多maximumPoolSize+queue
        //                      拒绝执行

//        threadPool.execute(new MyRunnable3());//适用于Runnable
//        threadPool.submit(new MyCallable2());//适用于Callable
        //不用一个一个new Thread()了   直接放在threadPool里  他给你new Thread


//        ThreadPoolExecutor threadPoolExecutor= (ThreadPoolExecutor) threadPool;//强转一下   就可以用一些函数了
//        System.out.println(threadPoolExecutor.getPoolSize());//当前使用线程数
//        System.out.println(threadPoolExecutor.getCorePoolSize());//当前已有线程
        try{
            for (int i = 0; i < 10; i++) {
                final int k=i+1;
                threadPool.execute(()->{
                    try { TimeUnit.MILLISECONDS.sleep(s.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}
                    System.out.println(Thread.currentThread().getName() + "\t干活"+k);
                });
                //做完了  腾出位置 可以在做
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            threadPool.shutdown();//关闭线程池
        }
    }  //线程池   nTreads  几个线程  固定  线程  池

}
